package com.online.fund.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import com.online.fund.spider.dao.SharesMoniterConfigDao;
import com.online.fund.spider.entity.SharesMoniterConfig;
import com.online.fund.spider.entity.SharesTransactionMoniterData;
import com.online.fund.util.DateUtils;
import com.online.fund.util.HttpClientUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;

@Service
public class SharesMoniterService {
	
	private final static Logger logger = LoggerFactory.getLogger(SharesMoniterService.class);
	
	private final static String SHARES_PRICE_PAGE_URL = "http://nufm.dfcfw.com/EM_Finance2014NumericApplication/JS.aspx?&type=CT&sty=GB20GFBTC&st=z&js=((x))&token=4f1862fc3b5e77c150a2b985b12db0fd&cmd=#{sharesRefId}";
	
	@Resource
	private SharesMoniterConfigDao configDao;
	
	@Autowired
	private JavaMailSender mailSender;
	
	@Autowired  
	private Configuration configuration;
	
	@Value("${spring.mail.username}")
	private String fromMailAddress;
	
	private ExecutorService pool = Executors.newFixedThreadPool(20);

	/**
	 * 获取股票实时数据
	 */
	public void moniterSharesPrice() {
		// 1.获取需要监听的股票列表数据
		List<SharesMoniterConfig> sharesList = configDao.getSharesMoniterConfigList(1);
		
		// 2.使用线程获取实时的数据
		for (SharesMoniterConfig entity : sharesList) {
			pool.execute(() -> {
				try {
					processSharesData(entity, true);
				} catch (Exception e) {
					logger.error("获取股票实时数据错误：" + entity, e);
				}
			});
		}
	}
	
	/**
	 * 从数据库中取出需要发送的数据，组装数据模板，发送邮件通知
	 * @throws Exception 
	 */
	public void sendEmailNotify() throws Exception {
		// 获取待通知的数据列表
		List<SharesTransactionMoniterData> dataList = configDao.getSharesTransactionMoniterDataList(1);
		
		if (!dataList.isEmpty()) {
			// 按邮件地址分组，发送邮件
			Map<String, List<SharesTransactionMoniterData>> contentMap = new HashMap<>();
			for (SharesTransactionMoniterData sharesData : dataList) {
				if (sharesData.getNotifyEmail().contains(",")) {
					String[] emailArr = sharesData.getNotifyEmail().split(",");
					for (int i = 0; i < emailArr.length; i++) {
						processEmailAddressContent(contentMap, emailArr[i], sharesData);
					}
				} else {
					processEmailAddressContent(contentMap, sharesData.getNotifyEmail(), sharesData);
				}
			}
			
			// 按模板发送邮件
			for (Map.Entry<String, List<SharesTransactionMoniterData>> entry : contentMap.entrySet()) {
				sendSharesDataMail(entry.getKey(), entry.getValue());
			}
			
			// 更新数据
			for (SharesTransactionMoniterData sharesData : dataList) {
				Integer notifyStatus = 3;
				configDao.updateSharesTransactionMoniterDataNotifyStatus(notifyStatus, sharesData.getSharesTransactionMonitorId());
			}
		}
		
	}

	private void sendSharesDataMail(String mailAddress, List<SharesTransactionMoniterData> mailContentList) throws Exception {
		MimeMessage mimeMessage = mailSender.createMimeMessage();

		MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//		System.out.println(fromMailAddress);
		helper.setFrom(fromMailAddress);
		helper.setTo(mailAddress);
		helper.setSubject(DateUtils.getCurrentDate() + "股票价格变动通知");

		Map<String, Object> model = new HashMap<String, Object>();
		model.put("mailContentList", mailContentList);
		Template t = configuration.getTemplate("sharesMailTemplate.ftl"); // freeMarker template  
		String text = FreeMarkerTemplateUtils.processTemplateIntoString(t, model); 
//		System.out.println(text);
		helper.setText(text, true);

		mailSender.send(mimeMessage);

		
	}

	private void processEmailAddressContent(Map<String, List<SharesTransactionMoniterData>> contentMap,
			String mailAddress, SharesTransactionMoniterData sharesData) {
		List<SharesTransactionMoniterData> mailContentList = contentMap.get(mailAddress);
		if (mailContentList == null) {
			mailContentList = new ArrayList<>();
		}
		
		mailContentList.add(sharesData);
		contentMap.put(mailAddress, mailContentList);
		
	}

	public void processSharesData(SharesMoniterConfig entity, boolean saveFlag) throws IOException {
//		System.out.println(entity);
		String resultStr = HttpClientUtil.httpGetRequest(SHARES_PRICE_PAGE_URL.replace("#{sharesRefId}", entity.getRefId()), 5);
//		System.out.println(resultStr);
		if (resultStr != null && resultStr.length() > 4) {
			resultStr = resultStr.substring(2, resultStr.length() - 2);
			String[] sharesInfoArr = resultStr.split(",");
			if (sharesInfoArr.length > 9 && !sharesInfoArr[6].equals("-")) {
				Double currentPrice = Double.parseDouble(sharesInfoArr[5]);
				// 涨跌额
				Double changeAmount = Double.parseDouble(sharesInfoArr[6]);
				// 涨跌幅
				Double riseFallRate = Double.parseDouble(sharesInfoArr[7]);
				// 1：股票变动百分比，2：股票变动价格
				double priceAmount = entity.getDataMonitorType() == 1 ? Math.abs(riseFallRate) : Math.abs(changeAmount);
				
				SharesTransactionMoniterData moniterData = new SharesTransactionMoniterData();
				moniterData.setSharesCode(entity.getSharesCode());
				moniterData.setSharesName(entity.getSharesName());
				moniterData.setRefId(entity.getRefId());
				moniterData.setMonitorConfigId(entity.getId());
				moniterData.setNotifyEmail(entity.getNotifyEmail());
				moniterData.setLatestPrice(currentPrice);
				moniterData.setChangeAmount(changeAmount);
				moniterData.setRiseFallRate(riseFallRate);
				moniterData.setTransactionDate(sharesInfoArr[10]);
				
				boolean notifyFlag = false;
				// 判断下跌是否需要通知
				if (entity.getMinValue() != null && changeAmount < 0) {
					if (entity.getMinValue() < priceAmount) {
						moniterData.setRiseFallFlag(2);
						notifyFlag = true;
					}
				} else if (entity.getMaxValue() != null && changeAmount > 0) {
					if (entity.getMaxValue() < priceAmount) {
						moniterData.setRiseFallFlag(1);
						notifyFlag = true;
					}
				}
				
				// 存储股票价格数据
				if (notifyFlag) {
					moniterData.setNotyfyStatus(checkSharesNotityStatus(moniterData));
					
					if (saveFlag) {
						configDao.saveSharesTransactionMoniterData(moniterData);
					} else {
						System.out.println(moniterData);	
					}
					
				}
			}
			
			if (!saveFlag) {
				System.out.println(resultStr);
			}
			
		}
	}
	
	/**
	 * 判断当前股票是否需要发邮件通知(同一支股票价格变动在5分钟内不在重复通知，超过5分钟价格相同的也不在发邮件通知)
	 * @param moniterData
	 * @return 0：不需要通知，1：等待通知
	 */
	private Integer checkSharesNotityStatus(SharesTransactionMoniterData moniterData) {
		String sharesCode = moniterData.getSharesCode();
		Long monitorConfigId = moniterData.getMonitorConfigId();
		// 前一次通知时的价格、时间
		SharesTransactionMoniterData dbMoniterData = configDao.getLatestSharesTransactionMoniterData(sharesCode, monitorConfigId);
		// 以前没发送过通知
		if (dbMoniterData == null) {
			return 1;
		}
		
		String format = "yyyy-MM-dd HH:mm:ss";
		String datetime = DateUtils.getCurrentDatetime();
		Long diff = DateUtils.dateDiff(dbMoniterData.getNotifyDate(), datetime, format, "s");
		// 5分钟内不重复发送邮件
		if (diff.longValue() < 300) {
			return 0;
		} else if (dbMoniterData.getLatestPrice().doubleValue() == moniterData.getLatestPrice().doubleValue()) {
			// 时间超过5分钟，但价格未变动的(涨停、跌停)，也不再发送通知
			return 0;
		}
		return 1;
	}
	
	/**
	 * 外部测试释放资源方法
	 * @throws Exception
	 */
	public void releaseResource() throws Exception {
		pool.shutdown();
		while (!pool.isTerminated()) {
			Thread.sleep(1000);
		}
		HttpClientUtil.closeConnectionPool();

	}

	public static void main(String[] args) throws Exception {
		SharesMoniterService service = new SharesMoniterService();
		SharesMoniterConfig entity = new SharesMoniterConfig();
		entity.setRefId("6000361");
		// 股票上涨比例
		entity.setDataMonitorType(1);
		entity.setMaxValue(1D);
		service.processSharesData(entity, false);
		
		service.pool.shutdown();
		while (!service.pool.isTerminated()) {
			Thread.sleep(1000);
		}
		HttpClientUtil.closeConnectionPool();
	}
	
}
